package com.xiyuan.smartutils;

import com.xiyuan.smartutils.constants.CodeConstants;
import com.xiyuan.smartutils.constants.EnumConstants;
import com.xiyuan.smartutils.crypto.HEX;
import com.xiyuan.smartutils.enums.LetterCase;

import java.nio.charset.Charset;

import static com.xiyuan.smartutils.csv.Constants.EMPTY;

/**
 * 十六进制相关工具类
 *
 * @version v1.0.0 @author lgz 2017-8-27 新建与整理
 */

@SuppressWarnings({"all"})
public final class Hexs implements CodeConstants, EnumConstants {
    
    private Hexs(){}
    /**
     * 得到字符串对应的16进制编码
     */
    public static String toHexStringUTF8(String str) {
        return toHexString(str.getBytes(_UTF_8_C_));
    }
    
    /**
     * 字节数组转字符串，顺序解析
     */
    public static String toHexString(int b) {
//        return Integer.toHexString((b & 0xFF)+0x100).substring(1);
        return Integer.toHexString(b);
    }
    
    /**
     * 字节数组转字符串，顺序解析
     */
    public static String toHexString(byte[] b) {
        return toHexString(b, LetterCase.LOWER);
    }
    
    /**
     * 字节数组转字符串，顺序解析
     */
    public static String toHexString(byte[] b, LetterCase letterCase) {
        return toHexString(b, _EMPTY_, letterCase);
    }
    
    /**
     * 字符串转字节数组，顺序解析
     */
    public static String toHexString(byte[] b, String spe) {
        return toHexString(b, spe, LetterCase.LOWER);
    }
    
    /**
     * 字符串转字节数组，顺序解析，指定大小写
     */
    public static String toHexString(byte[] b, String spe, LetterCase letterCase) {
        return HEX.toString(spe, letterCase, b);
    }
    
    /**
     * &#x;十六进制编码
     *
     * @param s 转化为&#x;型的十六制编码
     * @return String &#x3423;&#x3423;十六进制编码
     */
    public static String toHexStringX(String s) {
        return toHexString(s, "&#x", ";", null);
    }
    
    /**
     * \\u十六进制编码
     *
     * @param s 字符串
     * @return String \\u3423\\u4523十六进制编码
     */
    public static String toHexStringU(String s) {
        return toHexString(s, "\\u", null, null);
    }
    
    /**
     * U+十六进制编码,且去重
     *
     * @param s 字符串
     * @return String U+6211,U+7684十六进制编码
     */
    public static String toHexStringUPlus(String s) {
        String u = toHexString(s, "U+", null, ",");
        return Arrays.toFilterSameStr(u.split(","), ",");
    }
    
    /**
     * 转化为unicode十六进制编码
     *
     * @param s         字符串
     * @param prefix    Unicode前缀，如0x,U+等
     * @param suffix    Unicode前缀，如;
     * @param separator 分隔符，如逗号和空格等
     * @return Unicode编码如"我的"值为0x6211 0x7684或U+6211,U+7684
     */
    public static String toHexString(String s, String prefix, String suffix, String separator) {
        if (Validates.isEmpty(s)) {return _EMPTY_;}
        
        StringBuilder strb = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            
            if (prefix != null) {strb.append(prefix);}
            
            strb.append(Integer.toHexString(c));
            
            if (suffix != null) {strb.append(suffix);}
            
            if (separator != null) {strb.append(separator);}
        }
        
        if (s.length() > 0 && separator != null) {strb.setLength(strb.length() - separator.length());}
        
        return strb.toString();
    }
    
    /*******************************************************************/
    //HEX字符串转化为byte[]
    /*******************************************************************/
    
    /**
     * HEX 转bytes, 支持HEX中间加空格, Integer.parseInt写法
     */
    public static byte[] toBytes(String hex) {
        return toBytes(hex, hex != null && hex.indexOf(_ONE_SPACE_) != -1 ? _ONE_SPACE_ : null);
    }
    
    /**
     * HEX 转bytes, 支持HEX中间加分隔符, Integer.parseInt写法
     */
    public static byte[] toBytes(String hex, String spe) {
        return HEX.toBytes(hex, spe);
    }
    

    /**
     * 把字节转换为16进制字符
     */
    public static String byteToHex(byte ib) {
        char[] ob = new char[2];
        ob[0] = _HEX_CHAR_[(ib >>> 4) & 0x0F];
        ob[1] = _HEX_CHAR_[ib & 0x0F];
        return new String(ob);
    }
    
    /**
     * 把字节转换为16进制字符
     */
    public static String byteToHexLower(byte ib) {
        char[] ob = new char[2];
        ob[0] = _HEX_CHAR_LOW_[(ib >>> 4) & 0x0F];
        ob[1] = _HEX_CHAR_LOW_[ib & 0x0F];
        return new String(ob);
    }
    
    /**
     * 把16进制字符转字节
     */
    public static int hexToByte(char c) {
        if (Character.isDigit(c)) {
            return c - _0_;
        }
        else if (Character.isLowerCase(c)) {
            return 10 + c - _a_;
        }
        else {
            return 10 + c - _A_;
        }
    }
    
    /**
     * 把字节数组转换成二进制字符串
     */
    public static String toBinString(byte[] b, String spe) {
        if (b == null || b.length == 0) {return _EMPTY_;}
        
        StringBuilder strb = new StringBuilder();
        strb.append(byteToBin(b[0]));
        for (int i = 1; i < b.length; i++) {
            strb.append(spe).append(byteToBin(b[i]));
        }
        
        return strb.toString();
    }
    
    /**
     * 把字节转换为二进制字符
     */
    public static String byteToBin(byte ib) {
        char[] bin = new char[8];
        bin[0] = _BIN_CHAR_[(ib >>> 7) & 0x00000001];
        bin[1] = _BIN_CHAR_[(ib >>> 6) & 0x00000001];
        bin[2] = _BIN_CHAR_[(ib >>> 5) & 0x00000001];
        bin[3] = _BIN_CHAR_[(ib >>> 4) & 0x00000001];
        bin[4] = _BIN_CHAR_[(ib >>> 3) & 0x00000001];
        bin[5] = _BIN_CHAR_[(ib >>> 2) & 0x00000001];
        bin[6] = _BIN_CHAR_[(ib >>> 1) & 0x00000001];
        bin[7] = _BIN_CHAR_[ib & 0x00000001];
        return new String(bin);
    }
    
    /**
     * 16进制字符串，转字符串<br>
     * 例如：<br>
     * hex = 0x65sf--0x66sf--0x88sf<br>
     * 0x：表示前缀
     * sf：表示后缀
     * --：表示分隔符
     *
     * @param payload 16进制字符串
     * @param charset 字符串编码
     * @param sep     16进制字符串中的单位分隔符，比如：65--50--66   其中-- 属于分割符。默认为空
     * @param prefix  16进制字符串中的单位前缀符，比如：0x650x660x88 其中0x 属于前缀，默认为空
     * @param suffix  16进制字符串中的单位后缀符，比如：65xx66xx88xx 其中xx 属于后缀。默认为空
     * @return 转换后的字符串
     */
    public static String fromHex(String payload, Charset charset, String sep, String prefix, String suffix) {
        byte[] bytes = HEX.toBytes(payload, sep, prefix, suffix);
        return charset == null ? new String(bytes) : new String(bytes, charset);
    }
    
    
    /**
     * 16进制字符串，转字符串<br>
     * 例如：<br>
     * hex = 0x65--0x66--0x88<br>
     * 0x：表示前缀
     * --：表示分隔符
     *
     * @param payload 16进制字符串
     * @param charset 字符串编码
     * @param sep     16进制字符串中的单位分隔符，比如：65--50--66   其中-- 属于分割符。默认为空
     * @param prefix  16进制字符串中的单位前缀符，比如：0x650x660x88 其中0x 属于前缀，默认为空
     * @return 转换后的字符串
     */
    public static String fromHex(String payload, Charset charset, String sep, String prefix) {
        return fromHex(payload, charset, sep, prefix, EMPTY);
    }
    
    /**
     * 16进制字符串，转字符串<br>
     * 例如：<br>
     * hex = 65--66--88<br>
     * --：表示分隔符
     *
     * @param payload 16进制字符串
     * @param charset 字符串编码
     * @param sep     16进制字符串中的单位分隔符，比如：65--50--66   其中-- 属于分割符。默认为空
     * @return 转换后的字符串
     */
    public static String fromHex(String payload, Charset charset, String sep) {
        return fromHex(payload, charset, sep, EMPTY, EMPTY);
    }
    
    /**
     * 16进制字符串，转字符串<br>
     *
     * @param payload 16进制字符串
     * @param charset 字符串编码
     * @return 转换后的字符串
     */
    public static String fromHex(String payload, Charset charset) {
        return fromHex(payload, charset, EMPTY, EMPTY, EMPTY);
    }
    
    
    /**
     * 16进制字符串，转字符串<br>
     *
     * @param payload 16进制字符串
     * @param sep     16进制字符串中的单位分隔符，比如：65--50--66   其中-- 属于分割符。默认为空
     * @return 转换后的字符串
     */
    public static String fromHex(String payload, String sep) {
        return fromHex(payload, null, sep, EMPTY, EMPTY);
    }
    
    /**
     * 16进制字符串，转字符串
     *
     * @param payload 16进制字符串
     * @return 转换后的字符串
     */
    public static String fromHex(String payload) {
        return fromHex(payload, null, EMPTY, EMPTY, EMPTY);
    }
    
    
    /**
     * 16进制字符串，转字符串
     *
     * @param payload 16进制字符串
     * @return 转换后的UTF8编码的字符串
     */
    public static String fromHexUTF8(String payload) {
        return fromHex(payload, _UTF_8_C_, EMPTY, EMPTY, EMPTY);
    }
}
